package reflection;

import java.io.FileInputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Properties;

/**
 * 反射
 */
public class Reflection01 {

    public static void main(String[] args) throws Exception {

        /*
            1)反射机制允许程序在执行期间借助于Reflection API 取得任何类的内部信息(成员变量，构造器，成员方法等)
              并能操作对象的属性及方法。反射在设计模式和框架底层都会用到
            2)加载完类之后，在堆中就产生了一个Class类型的对象(一个类只有一个Class对象)，这个对象包含了类的完整结构信息。
              通过这个对象得到类的结构。这个对象就像一面镜子，透过这个镜子看到类的结构，所以，形象地称为：反射

              p对象 -> 类型 Person 类
              对象cls -> 类型 Class 类

              Java反射机制可以完成
              1.在运行时判断任意一个对象所属的类
              2.在运行时构造任意一个类的对象
              3.在运行时得到任意一个类所具有的成员变量和方法
              4.在运行时调用任意一个对象的成员变量和方法
              5.生成动态代理
         */

        /*
            反射相关的主要类
            Class  代表一个类，Class对象表示某个类在加载后在堆中的对象
            Method 代表类的方法
            Field  代表类的成员方法
            Constructor  代表类的构造方法

            这些类可以在java.lang.reflection中查看
         */
        //使用Properties读写配置文件
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\re.properties"));
        String classFullPath = properties.get("classfullpath").toString();//reflection.Cat
        String methodName = properties.get("method").toString();//hi
        System.out.println("classFullPath: " + classFullPath);
        System.out.println("methodName: " + methodName);

        //传统方法没法创建对象
        //new classfullpath();

        //创建对象，利用反射机制
        //1.加载类，返回Class类型的对象 cls
        Class cls = Class.forName(classFullPath);
        //2.通过 cls 得到加载的类 reflection.Cat 的对象实例
        Object o = cls.newInstance();
        System.out.println("o的运行类型=" + o.getClass());   //运行类型
        //3.通过 cls 得到加载的类 reflection.Cat 的 methodName "hi"的方法对象
        //即：在反射中，可以把方法视为对象(万物都是对象)
        Method method = cls.getMethod(methodName);
        //4.通过method1调用方法：即通过方法对象来实现调用方法
        System.out.println("==================================");
        method.invoke(o);   //传统方法 对象.方法()，反射机制 方法.invoke(对象)


        //得到 name 字段
        //getField() 不能得到私有的属性
        Field nameField = cls.getField("name");
        System.out.println(nameField.get(o));   //传统 对象.属性，反射 成员变量对象.get(对象)

        //得到构造器
        //可以指定参数类型,默认返回无参构造器
        Constructor constructor = cls.getConstructor();
        System.out.println(constructor);
        //传入的是构造器形参的类的对象
        Constructor constructor2 = cls.getConstructor(String.class);
        System.out.println(constructor2);
    }
}
